#pragma once

#if                                                                            \
  defined (__CYGWIN__)                                                      || \
  defined (__CYGWIN32__)
#  define NODE_EDITOR_PLATFORM "Cygwin"
#  define NODE_EDITOR_PLATFORM_CYGWIN
#  define NODE_EDITOR_PLATFORM_UNIX
#  define NODE_EDITOR_PLATFORM_WINDOWS
#elif                                                                          \
  defined (_WIN16)                                                          || \
  defined (_WIN32)                                                          || \
  defined (_WIN64)                                                          || \
  defined (__WIN32__)                                                       || \
  defined (__TOS_WIN__)                                                     || \
  defined (__WINDOWS__)
#  define NODE_EDITOR_PLATFORM "Windows"
#  define NODE_EDITOR_PLATFORM_WINDOWS
#elif                                                                          \
  defined (macintosh)                                                       || \
  defined (Macintosh)                                                       || \
  defined (__TOS_MACOS__)                                                   || \
  (defined (__APPLE__) && defined (__MACH__))
#  define NODE_EDITOR_PLATFORM "Mac"
#  define NODE_EDITOR_PLATFORM_MAC
#  define NODE_EDITOR_PLATFORM_UNIX
#elif                                                                          \
  defined (linux)                                                           || \
  defined (__linux)                                                         || \
  defined (__linux__)                                                       || \
  defined (__TOS_LINUX__)
#  define NODE_EDITOR_PLATFORM "Linux"
#  define NODE_EDITOR_PLATFORM_LINUX
#  define NODE_EDITOR_PLATFORM_UNIX
#elif                                                                          \
  defined (__FreeBSD__)                                                     || \
  defined (__OpenBSD__)                                                     || \
  defined (__NetBSD__)                                                      || \
  defined (__bsdi__)                                                        || \
  defined (__DragonFly__)
#  define NODE_EDITOR_PLATFORM "BSD"
#  define NODE_EDITOR_PLATFORM_BSD
#  define NODE_EDITOR_PLATFORM_UNIX
#elif                                                                          \
  defined (sun)                                                             || \
  defined (__sun)
#  define NODE_EDITOR_PLATFORM "Solaris"
#  define NODE_EDITOR_PLATFORM_SOLARIS
#  define NODE_EDITOR_PLATFORM_UNIX
#elif                                                                          \
  defined (_AIX)                                                            || \
  defined (__TOS_AIX__)
#  define NODE_EDITOR_PLATFORM "AIX"
#  define NODE_EDITOR_PLATFORM_AIX
#  define NODE_EDITOR_PLATFORM_UNIX
#elif                                                                          \
  defined (hpux)                                                            || \
  defined (_hpux)                                                           || \
  defined (__hpux)
#  define NODE_EDITOR_PLATFORM "HPUX"
#  define NODE_EDITOR_PLATFORM_HPUX
#  define NODE_EDITOR_PLATFORM_UNIX
#elif \
  defined (__QNX__)
#  define NODE_EDITOR_PLATFORM "QNX"
#  define NODE_EDITOR_PLATFORM_QNX
#  define NODE_EDITOR_PLATFORM_UNIX
#elif                                                                          \
  defined (unix)                                                            || \
  defined (__unix)                                                          || \
  defined (__unix__)
#  define NODE_EDITOR_PLATFORM "Unix"
#  define NODE_EDITOR_PLATFORM_UNIX
#endif

#ifndef NODE_EDITOR_PLATFORM
#  error "Current platform is not supported."
#endif

#if                                                               \
  defined (__MINGW32__)                                        || \
  defined (__MINGW64__)
#  define NODE_EDITOR_COMPILER "MinGW"
#  define NODE_EDITOR_COMPILER_MINGW
#elif \
  defined (__GNUC__)
#  define NODE_EDITOR_COMPILER "GNU"
#  define NODE_EDITOR_COMPILER_GNU
#  define NODE_EDITOR_COMPILER_GNU_VERSION_MAJOR __GNUC__
#  define NODE_EDITOR_COMPILER_GNU_VERSION_MINOR __GNUC_MINOR__
#  define NODE_EDITOR_COMPILER_GNU_VERSION_PATCH __GNUC_PATCHLEVEL__
#elif \
  defined (__clang__)
#  define NODE_EDITOR_COMPILER "Clang"
#  define NODE_EDITOR_COMPILER_CLANG
#elif \
  defined (_MSC_VER)
#  define NODE_EDITOR_COMPILER "Microsoft Visual C++"
#  define NODE_EDITOR_COMPILER_MICROSOFT
#elif \
  defined (__BORLANDC__)
#  define NODE_EDITOR_COMPILER "Borland C++ Builder"
#  define NODE_EDITOR_COMPILER_BORLAND
#elif \
  defined (__CODEGEARC__)
#  define NODE_EDITOR_COMPILER "CodeGear C++ Builder"
#  define NODE_EDITOR_COMPILER_CODEGEAR
#elif                                                             \
  defined (__INTEL_COMPILER)                                   || \
  defined (__ICL)
#  define NODE_EDITOR_COMPILER "Intel C++"
#  define NODE_EDITOR_COMPILER_INTEL
#elif                                                             \
  defined (__xlC__)                                            || \
  defined (__IBMCPP__)
#  define NODE_EDITOR_COMPILER "IBM XL C++"
#  define NODE_EDITOR_COMPILER_IBM
#elif \
  defined (__HP_aCC)
#  define NODE_EDITOR_COMPILER "HP aC++"
#  define NODE_EDITOR_COMPILER_HP
#elif \
  defined (__WATCOMC__)
#  define NODE_EDITOR_COMPILER "Watcom C++"
#  define NODE_EDITOR_COMPILER_WATCOM
#endif

#ifndef NODE_EDITOR_COMPILER
#  error "Current compiler is not supported."
#endif

#ifdef NODE_EDITOR_PLATFORM_WINDOWS
#  define NODE_EDITOR_EXPORT __declspec(dllexport)
#  define NODE_EDITOR_IMPORT __declspec(dllimport)
#  define NODE_EDITOR_LOCAL
#elif                                                           \
  NODE_EDITOR_COMPILER_GNU_VERSION_MAJOR >= 4                         || \
  defined (NODE_EDITOR_COMPILER_CLANG)
#  define NODE_EDITOR_EXPORT __attribute__((visibility("default")))
#  define NODE_EDITOR_IMPORT __attribute__((visibility("default")))
#  define NODE_EDITOR_LOCAL  __attribute__((visibility("hidden")))
#else
#  define NODE_EDITOR_EXPORT
#  define NODE_EDITOR_IMPORT
#  define NODE_EDITOR_LOCAL
#endif

#ifdef __cplusplus
#  define NODE_EDITOR_DEMANGLED extern "C"
#else
#  define NODE_EDITOR_DEMANGLED
#endif


#if defined (NODE_EDITOR_SHARED) && !defined (NODE_EDITOR_STATIC)
#  ifdef NODE_EDITOR_EXPORTS
#    define NODE_EDITOR_PUBLIC NODE_EDITOR_EXPORT
#  else
#    define NODE_EDITOR_PUBLIC NODE_EDITOR_IMPORT
#  endif
#  define NODE_EDITOR_PRIVATE NODE_EDITOR_LOCAL
#elif !defined (NODE_EDITOR_SHARED) && defined (NODE_EDITOR_STATIC)
#  define NODE_EDITOR_PUBLIC
#  define NODE_EDITOR_PRIVATE
#elif defined (NODE_EDITOR_SHARED) && defined (NODE_EDITOR_STATIC)
#  ifdef NODE_EDITOR_EXPORTS
#    error "Cannot build as shared and static simultaneously."
#  else
#    error "Cannot link against shared and static simultaneously."
#  endif
#else
#  ifdef NODE_EDITOR_EXPORTS
#    error "Choose whether to build as shared or static."
#  else
#    error "Choose whether to link against shared or static."
#  endif
#endif

#include <functional>
#include <memory>
#include <utility>

#include <QtGlobal>
#include <QString>
#include <QtCore/QUuid>
#include <QtCore/QVariant>

namespace Qt
{
	namespace detail {
#if (!defined(_MSC_VER) && (__cplusplus < 201300)) || \
    ( defined(_MSC_VER) && (_MSC_VER < 1800)) 
		//_MSC_VER == 1800 is Visual Studio 2013, which is already somewhat C++14 compilant, 
		// and it has make_unique in it's standard library implementation
		template<typename T, typename... Args>
		std::unique_ptr<T> make_unique(Args&&... args)
		{
			return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
		}
#else
		template<typename T, typename... Args>
		std::unique_ptr<T> make_unique(Args&&... args)
		{
			return std::make_unique<T>(std::forward<Args>(args)...);
		}
#endif
	}
}

namespace std
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
	template<>
	struct hash<QString>
	{
		inline std::size_t
			operator()(QString const &s) const
		{
			return qHash(s);
		}
	};
#endif

	template<>
	struct hash<QUuid>
	{
		inline
			std::size_t
			operator()(QUuid const& uid) const
		{
			return qHash(uid);
		}
	};
}